package com.xci.core.helper;

import cn.hutool.core.date.DateUtil;
import com.xci.core.internal.Const;

import javax.validation.constraints.NotNull;
import java.time.*;
import java.util.Date;

/**
 * 日期时间操作帮助类
 *
 * @author 吕艳阳
 */
public class DateHelper {

    /**
     * 获取当前日期
     *
     * @return 返回当前日期对象
     */
    public static Date now() {
        return new Date();
    }

    /**
     * 格式化日期(默认格式yyyy-MM-dd)
     *
     * @param date 指定的时间
     * @return 返回日期格式化后的字符串
     */
    public static String formatDate(Date date) {
        return format(date, Const.DEFAULT_DATE_PATTERN);
    }

    /**
     * 格式化日期字符串(默认格式 yyyy-MM-dd HH:mm)
     *
     * @param date 指定的时间
     * @return 返回日期格式化后的字符串
     */
    public static String formatDateHasMinute(Date date) {
        return format(date, Const.DEFAULT_DATE_MS_PATTERN);
    }

    /**
     * 格式化日期(默认格式 yyyy-MM-dd HH:mm:ss)
     *
     * @param date 指定的时间
     * @return 返回日期格式化后的字符串
     */
    public static String formatDateTime(Date date) {
        return format(date, Const.DEFAULT_DATETIME_PATTERN);
    }

    /**
     * 获取格式化的时间字符串(默认格式 HH:mm:ss)
     *
     * @param date 指定的时间
     * @return 返回日期格式化后的字符串
     */
    public static String formatTime(Date date) {
        return format(date, Const.DEFAULT_TIME_PATTERN);
    }

    /**
     * 格式化日期
     *
     * @param date   指定的时间
     * @param format 格式字符串
     * @return 返回日期格式化后的字符串
     */
    public static String format(Date date, String format) {
        if (date == null) {
            return "";
        }
        return DateUtil.format(date, format);
    }

    /**
     * 日期对象转为本地日期时间对象
     *
     * @param date 日期对象
     * @return 本地日期时间对象
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    /**
     * 日期对象转为本地日期对象
     *
     * @param date 日期对象
     * @return 本地日期对象
     */
    public static LocalDate dateToLocalDate(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        return localDateTime.toLocalDate();
    }

    /**
     * 日期对象转为本地时间对象
     *
     * @param date 日期对象
     * @return 本地时间对象
     */
    public static LocalTime dateToLocalTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        return localDateTime.toLocalTime();
    }

    /**
     * 本地日期对象转为日期对象
     *
     * @param localDate 本地日期对象
     * @return 日期对象
     */
    public static Date localDateToDate(LocalDate localDate) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * 本地日期时间对象转为日期对象
     *
     * @param localDateTime 本地日期时间对象
     * @return 日期对象
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * 本地日期和本地时间对象转为日期对象
     *
     * @param localDate 本地日期对象
     * @param localTime 本地时间对象
     * @return 日期对象
     */
    public static Date localDateTimeToDate(LocalDate localDate, LocalTime localTime) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = LocalDateTime.of(localDate, localTime).atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * 测试检测时间是否在指定的开始时间和结束时间之内,精度到毫秒单位,如果不在范围内返回true
     * @param checkedDate 检测时间
     * @param startTime 开始时间
     * @param endTime 结束日时间
     * @return 如果在开始时间和结束时间范围内返回false,否则返回true
     */
    public static boolean isExpired(@NotNull Date checkedDate, Date startTime, Date endTime) {
        long checkedTime = checkedDate.getTime();
        return (startTime != null && startTime.getTime() >= checkedTime)
                || (endTime != null && endTime.getTime() <= checkedTime);
    }
}